home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / gnulib / libsrc98.zoo / symdir.c < prev    next >
C/C++ Source or Header  |  1992-06-24  |  7KB  |  388 lines

  1. /*
  2.  * _read_symdir(), _write_symdir(), _free_symdir(): routines for
  3.  * reading/writing the special directories used for symbolic links.
  4.  * If symbolic links were not set active in UNIXMODE, then theses
  5.  * routines are no-ops.
  6.  *
  7.  * Written by Eric R. Smith and placed in the public domain. Use
  8.  * at your own risk.
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <osbind.h>
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include <errno.h>
  16. #include "symdir.h"
  17.  
  18. #ifndef NAME_MAX
  19. #  include <limits.h>
  20. #endif
  21.  
  22. #ifndef _LIB_NAME_MAX
  23. #  define _LIB_NAME_MAX NAME_MAX
  24. #endif
  25.  
  26. /*
  27.  * utility routine to provide buffered I/O for _read_symdir()
  28.  */
  29.  
  30. #define ResetFgetc() Fgetc(-1)
  31.  
  32. static int Fgetc(fd)
  33.     int fd;
  34. {
  35.     static unsigned char buf[BUFSIZ], *pos;
  36.     static int siz = 0;
  37.  
  38.     if (fd < 0) {
  39.         siz = 0; pos = buf; return 0;
  40.     }
  41.  
  42.     if (siz == 0) {
  43.         siz = Fread(fd, BUFSIZ, buf);
  44.         pos = buf;
  45.         if (siz <= 0) {
  46.             siz = 0; pos = buf; return -1;
  47.         }
  48.     }
  49.     siz--;
  50.     return *pos++;
  51. }
  52.  
  53.  
  54. /*
  55.  * Routines for keeping a cache of recently used symbolic directories.
  56.  * The last 8 directories accessed are kept cached; this really helps
  57.  * the directory searches in _unx2dos, but does eat some memory.
  58.  *
  59.  * entries are added to the cache by _free_symdir, and removed if they
  60.  * fall off the end, or if they're retrieved by a subsequent _read_symdir.
  61.  *
  62.  * IMPLICIT ASSUMPTION: the same directory is never open more than once.
  63.  */
  64.  
  65. #define CACHESIZE 8
  66.  
  67. static SYMDIR *in_cache;
  68.  
  69. static
  70. SYMDIR *_cache_lookup(pth)
  71.     const char *pth;
  72. {
  73.     SYMDIR **prev = &in_cache, *cur = *prev;
  74.  
  75.     while (cur) {
  76.         if (!strcmp(cur->s_pth, pth)) {
  77. /* remove from cache */
  78.             *prev = cur->s_nxt;
  79.             cur->s_nxt = 0;
  80.             return cur;
  81.         }
  82.         prev = &cur->s_nxt; cur = *prev;
  83.     }
  84.     return 0;
  85. }
  86.  
  87. static
  88. void
  89. _cache_add(cur)
  90.     SYMDIR *cur;
  91. {
  92.     SYMDIR *nxt = 0;
  93.     SYMENTRY *dir, *old;
  94.  
  95.     int count = 0;
  96.  
  97.     cur->s_nxt = in_cache;
  98.     in_cache = cur;
  99.     while (cur) {
  100.         nxt = cur->s_nxt;
  101.         ++count;
  102.         if (count == CACHESIZE)
  103.             cur->s_nxt = 0;
  104.         else if (count > CACHESIZE) {
  105.             dir = cur->s_dir;
  106.             while (dir) {
  107.                 old = dir;
  108.                 dir = dir->next;
  109.                 free(old);
  110.             }
  111.             free(cur->s_pth);
  112.             free(cur);
  113.         }
  114.         cur = nxt;
  115.     }
  116. }
  117.  
  118. /*
  119.  * free a symbolic directory. Note that _unx2dos is expecting the entries
  120.  * to be accessible, i.e. it knows that we're caching at least 1 directory.
  121.  * If this ever changes, change _unx2dos.
  122.  */
  123.  
  124. void _free_symdir(dir)
  125.     SYMDIR *dir;
  126. {
  127.     if (dir)
  128.         _cache_add(dir);
  129. }
  130.  
  131. /*
  132.  * read in the symbolic directory corresponding to "path".
  133.  * the symdir must be removed from the cache, since it may
  134.  * be modified and written back via _write_symdir
  135.  */
  136.  
  137. SYMDIR *_read_symdir(path)
  138.     char *path;
  139. {
  140.     char dirname[FILENAME_MAX], tmp[2*FILENAME_MAX], *p;
  141.     int fd, c;
  142.     SYMENTRY *old, *new;
  143.     SYMDIR *dir;
  144.  
  145. /* check that symbolic links are active */
  146.     if (!_lOK) {
  147.         errno = EINVAL;
  148.         return NULL;
  149.     }
  150.  
  151.     strcpy(dirname, path);
  152.     strcat(dirname, "\\");
  153.     strcat(dirname, _lDIR);
  154.  
  155.     if (dir = _cache_lookup(dirname))
  156.         return dir;
  157.  
  158.     ResetFgetc();
  159.     fd = Fopen(dirname, 0);
  160.     if (fd < 0 && fd != -ENOENT) {
  161.         errno = -fd;
  162.         return NULL;
  163.     }
  164.  
  165.     dir = (SYMDIR *)malloc(sizeof(SYMDIR)+strlen(tmp)+1);
  166.     if (dir == NULL) {
  167.         errno = ENOMEM;
  168.         return dir;
  169.     }
  170.     dir->s_pth = strdup(dirname);
  171.     if (!dir->s_pth)
  172.         return NULL;
  173.     dir->s_nxt = 0;
  174.  
  175.     old = NULL;
  176.     if (fd == -ENOENT) goto done_directory;
  177.  
  178.     p = tmp;
  179.     while ( (c = Fgetc(fd)) >= 0 ) {
  180.         if (c == '\r') continue;
  181.         if (c == '\n') {
  182.             *p++ = 0;
  183.             new= (SYMENTRY *)malloc(sizeof(SYMENTRY)+strlen(tmp)+1);
  184.             if (new == 0) break;
  185.             strcpy(new->linkname, tmp);
  186.             new->linkto = new->linkname;
  187.             for (p = new->linkname; *p; p++) {
  188.                 if (*p == '\t') {
  189.                     *p++ = 0;
  190.                     new->linkto = p;
  191.                     break;
  192.                 }
  193.             }
  194. /*
  195.  * Now we should check for any further fields, such as "flags"
  196.  * it is very important that we save *all* the characters that were given
  197.  * in the flags field, as well as setting the bits we understand.
  198.  * That way, programs remain compatible with future versions of the
  199.  * standard.
  200.  */
  201.             for (;*p;p++) {
  202.                 if (*p == '\t') {
  203.                     *p++ = 0;
  204.                     break;
  205.                 }
  206.             }
  207.             new->cflags = p; /* save pointer to flag characters */
  208.             new->flags = 0;
  209.             for (;*p;p++) {
  210.                 if (*p == 'A')
  211.                     new->flags |= SD_AUTO;
  212.             }
  213.             new->next = old;
  214.             old = new;
  215.             p = tmp;
  216.         }
  217.         else
  218.             *p++ = c;
  219.     }
  220.     (void)Fclose(fd);
  221.  
  222. done_directory:
  223.     dir->s_dir = old;
  224.     return dir;
  225. }
  226.  
  227. /*
  228.  * write a symbolic directory out onto a path
  229.  */
  230.  
  231. int _write_symdir(path, dir)
  232.     char *path;
  233.     SYMDIR *dir;
  234. {
  235.     SYMENTRY *new;
  236.     int fd, r;
  237.     char dirname[FILENAME_MAX];
  238.  
  239. /* check to see that symbolic links are OK */
  240.     if (!_lOK)
  241.         return -EINVAL;
  242.  
  243.     strcpy(dirname, path);
  244.     strcat(dirname, "\\");
  245.     strcat(dirname, _lDIR);
  246.  
  247.     if (dir->s_dir == NULL) {
  248.         (void)Fdelete(dirname);
  249.         return 0;
  250.     }
  251.  
  252.     fd = Fcreate(dirname, 0);
  253.     if (fd < 0) {
  254.         return fd;
  255.     }
  256.  
  257.     for (new = dir->s_dir; new; new = new->next) {
  258.         (void)Fwrite(fd, strlen(new->linkname), new->linkname);
  259.         (void)Fwrite(fd, 1L, "\t");
  260.         (void)Fwrite(fd, strlen(new->linkto), new->linkto);
  261.         if (new->cflags[0]) {
  262.             (void)Fwrite(fd, 1L, "\t");
  263.             (void)Fwrite(fd, strlen(new->cflags), new->cflags);
  264.         }
  265.         r = Fwrite(fd, 1L, "\n");
  266.         if (r <= 0) {
  267.             (void)Fclose(fd);
  268.             return r;
  269.         }
  270.     }
  271.  
  272.     (void)Fclose(fd);
  273.     return 0;
  274. }
  275.  
  276. /*
  277.  * _symdir_lookup, _make_symlink: utility routines that are needed in
  278.  * various places
  279.  */
  280.  
  281. /*
  282.  * return the symbolic directory entry for "name", or NULL if it is not
  283.  * found
  284.  */
  285.  
  286. SYMENTRY *
  287. _symdir_lookup(dir, name)
  288.     SYMDIR *dir;
  289.     const char *name;
  290. {
  291.     SYMENTRY *ent;
  292.  
  293.     if (!dir) return 0;
  294.     for (ent = dir->s_dir; ent; ent = ent->next) {
  295.         if (!strcmp(ent->linkname, name))
  296.             return ent;
  297.     }
  298.     return 0;
  299. }
  300.  
  301. /*
  302.  * _make_autolink(dosname, source): make an "automatic" symbolic link,
  303.  * with name "source", to the file whose full canonical dos pathname is in
  304.  * "dosname". Returns 1 if link made, 0 if not. It checks the _lAUTO
  305.  * flag, so parent functions don't have to. Parents are responsible
  306.  * for dealing with any conflicts with existing files.
  307.  */
  308.  
  309. int _make_autolink(dosname, source)
  310.     char *dosname, *source;
  311. {
  312.     char path[FILENAME_MAX], oldname[_LIB_NAME_MAX];
  313.     char *s, *p;
  314.     SYMDIR *dir;
  315.     SYMENTRY *d;
  316.  
  317.     if (!_lAUTO)
  318.         return 0;
  319.  
  320.     strcpy(path, dosname);
  321.     if ((p = strrchr(path, '\\'))) {
  322.         *p++ = 0;
  323.         _dos2unx(p, oldname);
  324.     } else {
  325.         _dos2unx(path, oldname);
  326.         path[0] = 0;
  327.     }
  328.  
  329.     if (!(dir = _read_symdir(path)))
  330.         return 0;
  331.     d = (SYMENTRY *)
  332.         malloc(sizeof(SYMENTRY)+strlen(source)+strlen(oldname)+4);
  333.     if (d == 0) {
  334.         errno = ENOMEM;
  335.         return -1;
  336.         _free_symdir(dir);
  337.     }
  338. /*
  339.  * now set up the fields; remember to set the character flags (cflags) as well!
  340.  */
  341.     strcpy(d->linkname, source);
  342.     for (s = d->linkname; *s; s++)
  343.         ;
  344.     ++s;
  345.     d->linkto = s;
  346.     strcpy(s, oldname);
  347.     for (; *s; s++)
  348.         ;
  349.     ++s;
  350.     strcpy(s, "A");        /* AUTO flag */
  351.     d->cflags = s;
  352.     d->flags = SD_AUTO;
  353.     d->next = dir->s_dir;
  354.     dir->s_dir = d;
  355.     _write_symdir(path, dir);
  356.     return 1;
  357. }
  358.  
  359. static
  360. void
  361. _del_dir(cur)
  362.     SYMDIR *cur;
  363. {
  364.     SYMENTRY *dir, *old;
  365.  
  366.     dir = cur->s_dir;
  367.     while (dir) {
  368.         old = dir;
  369.         dir = dir->next;
  370.         free(old);
  371.     }
  372.     free(cur->s_pth);
  373.     free(cur);
  374. }
  375.  
  376. void
  377. _del_symdir_cache()
  378. {
  379.     SYMDIR *cur = in_cache, *nxt = 0;
  380.  
  381.     while (cur) {
  382.         nxt = cur->s_nxt;
  383.         _del_dir(cur);
  384.         cur = nxt;
  385.     }
  386.     in_cache = 0;
  387. }
  388.